/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.celephais.objectGenerator.fileGenerators;

import com.celephais.objectGenerator.FieldDetailPanel;
import com.celephais.objectGenerator.FieldDetailPanel.FieldType;
import com.celephais.objectGenerator.ObjectGenerator;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Eugene Shen
 */
public class ClientModelGenerator extends FileGenerator {

	protected static final String CLIENT_MODEL_TEMPL_DIR = "templates" + File.separator + "clientModel" + File.separator;

	// Get Value Templates.
	private String gvBool=null, gvDouble=null, gvInt=null, gvRef=null, gvSimp=null;

	// Set Value Templates.
	private String svBool=null, svDouble=null, svInt=null, svSimp=null;

	public ClientModelGenerator(ObjectGenerator parent) {
		super(parent);
	}

	@Override
	public String getTemplateDir() {
		return CLIENT_MODEL_TEMPL_DIR;
	}

	@Override
	public String generateAdditional(String fileContents) {
		// String constants for the fields.
		String strConsts = generateStringConsts();
		if (strConsts != null) {
			fileContents = fileContents.replaceAll("%stringConstants%", strConsts);
		}

		// Variable Declarations.
		String varDecl = generateVarDecls();
		if (varDecl != null) {
			fileContents = fileContents.replaceAll("%varDecl%", varDecl);
		}

		// TableColumn building.
		fileContents = fileContents.replaceAll("%numAddlCols%",
				Integer.toString(parent.getDetailsPanel().getFields().size()));
		String buildCols = generateBuildCols();
		if (buildCols != null) {
			fileContents = fileContents.replaceAll("%buildCols%", buildCols);
		}

		// Accessors.
		String accessors = generateAccessors();
		if (accessors != null) {
			fileContents = fileContents.replaceAll("%accessors%", accessors);
		}

		// getValue method.
		String getValue = generateGetValue();
		if (getValue != null) {
			fileContents = fileContents.replaceAll("%getValue%", getValue);
		}

		// setValue method.
		String setValue = generateSetValue();
		if (setValue != null) {
			fileContents = fileContents.replaceAll("%setValue%", setValue);
		}

		// reference methods.
		String refMethods = generateRefMethods();
		if (refMethods != null) {
			fileContents = fileContents.replaceAll("%referenceMethods%", refMethods);
		}

		return fileContents;
	}

	@Override
	public String getFileName(String baseClassName) {
		return baseClassName + "UI";
	}

	@Override
	public String getOutputDir(String srcDir) {
		return srcDir + File.separator + "client" + File.separator + "model";
	}

	protected String generateStringConsts() {
		StringBuilder rtn = new StringBuilder();
		String constTemplate = readFile(getTemplateDir(), "stringConstant.txt");
		for (FieldDetailPanel fdp : parent.getDetailsPanel().getFields()) {
			String name = fdp.getFieldName();
			String constName = getConstName(name);
			rtn.append(constTemplate.replaceAll("%varName%", name)
					.replaceAll("%varNameConst%", constName)); //.append(CRLF);
		}
		return rtn.toString();
	}

	protected String generateVarDecls() {
		StringBuilder rtn = new StringBuilder();
		String varDeclTemplate = readFile(getTemplateDir(), "varDecl.txt");
		for (FieldDetailPanel fdp : parent.getDetailsPanel().getFields()) {
			FieldType type = fdp.getType();
			String javaType = getJavaType(type);
			if (type != null) {
				rtn.append(varDeclTemplate.replaceAll("%type%", javaType)
						.replaceAll("%varName%", fdp.getFieldName())); //.append(CRLF);
			}
		}
		return rtn.toString();
	}

	protected String generateBuildCols() {
		StringBuilder rtn = new StringBuilder();
		String buildColTempl = readFile(getTemplateDir(), "tableColumn.txt");
		for (FieldDetailPanel fdp : parent.getDetailsPanel().getFields()) {
			String name = fdp.getFieldName();
			String constName = getConstName(name);
			name = getReadableName(name);
			rtn.append(buildColTempl.replaceAll("%varNameConst%", constName)
					.replaceAll("%varNameReadable%", name)
					.replaceAll("%displayType%", getDisplayType(fdp.getType()))); //.append(CRLF);
		}
		return rtn.toString();
	}

	protected String generateAccessors() {
		StringBuilder rtn = new StringBuilder();
		String accessTempl = readFile(getTemplateDir(), "accessor.txt");
		for (FieldDetailPanel fdp : parent.getDetailsPanel().getFields()) {
			String name = fdp.getFieldName();
			rtn.append(accessTempl.replaceAll("%type%", getJavaType(fdp.getType()))
					.replaceAll("%varNameUpper%", getNameUpper(name))
					.replaceAll("%varName%", name)); //.append(CRLF);
		}
		return rtn.toString();
	}

	protected String generateGetValue() {
		StringBuilder rtn = new StringBuilder();
		boolean first = true;
		for (FieldDetailPanel fdp : parent.getDetailsPanel().getFields()) {
			String name = fdp.getFieldName();
			String nameConst = getConstName(name);
			String nameUpper = getNameUpper(name);
			String templ = getGetValueTemplate(fdp.getType());
			if (templ != null) {
				if (first) {
					rtn.append("\t\t").append(templ
							.replaceAll("%varNameConst%", nameConst)
							.replaceAll("%varNameUpper%", nameUpper)); //.append(CRLF);
					first = false;
				}
				else {
					rtn.append("\t\telse ").append(templ
							.replaceAll("%varNameConst%", nameConst)
							.replaceAll("%varNameUpper%", nameUpper)); //.append(CRLF);
				}
			}
		}
		return rtn.toString();
	}

	protected String generateSetValue() {
		StringBuilder rtn = new StringBuilder();
		boolean first = true;
		for (FieldDetailPanel fdp : parent.getDetailsPanel().getFields()) {
			String name = fdp.getFieldName();
			String nameConst = getConstName(name);
			String nameUpper = getNameUpper(name);
			String templ = getSetValueTemplate(fdp.getType());
			if (templ != null) {
				if (first) {
					rtn.append("\t\t").append(templ
							.replaceAll("%varNameConst%", nameConst)
							.replaceAll("%varNameUpper%", nameUpper)); //.append(CRLF);
					first = false;
				}
				else {
					rtn.append("\t\telse ").append(templ
							.replaceAll("%varNameConst%", nameConst)
							.replaceAll("%varNameUpper%", nameUpper)); //.append(CRLF);
				}
			}
		}
		return rtn.toString();
	}

	protected String generateRefMethods() {
		if (!parent.getDetailsPanel().hasReferenceField()) {
			return "";
		}
		else {
			String refTempl = readFile(getTemplateDir(), "refBlock.txt").replaceAll("%className%", objName);
			String setRefTempl = readFile(getTemplateDir(), "setRef.txt");
			String getRefTempl = readFile(getTemplateDir(), "getRef.txt");
			String listValidRefsTempl = readFile(getTemplateDir(), "listValidRefs.txt");
			StringBuilder setRef = new StringBuilder();
			StringBuilder getRef = new StringBuilder();
			StringBuilder listValidRef = new StringBuilder();
			boolean first = true;
			for (FieldDetailPanel fdp : parent.getDetailsPanel().getFields()) {
				if (fdp.getType() == FieldType.REF) {
					String name = fdp.getFieldName();
					String nameConst = getConstName(name);
					String nameUpper = getNameUpper(name);
					String prefix = first ? "\t\t" : "\t\telse ";
					
					setRef.append(prefix).append(setRefTempl
							.replaceAll("%varNameConst%", nameConst)
							.replaceAll("%varNameUpper%", nameUpper)); //.append(CRLF);
					getRef.append(prefix).append(getRefTempl
							.replaceAll("%varNameConst%", nameConst)
							.replaceAll("%varNameUpper%", nameUpper)); //.append(CRLF);
					listValidRef.append(prefix).append(listValidRefsTempl
							.replaceAll("%refNameConst%", nameConst)); //.append(CRLF);
				}
			}

			return refTempl.replaceAll("%getRef%", getRef.toString())
					.replaceAll("%setRef%", setRef.toString())
					.replaceAll("%listValidRefs%", listValidRef.toString());
		}
	}

	// Helper Methods

	protected String getNameUpper(String name) {
		return name.substring(0, 1).toUpperCase() + name.substring(1);
	}

	protected String getConstName(String name) {
		String constName = name;
		for (int i=1; i<constName.length(); ++i) {
			if (Character.isUpperCase(constName.charAt(i))) {
				constName = constName.substring(0, i) + "_" + constName.substring(i);
				++i;
			}
		}
		return constName.toUpperCase();
	}

	protected String getReadableName(String name) {
		String readableName = name.substring(0, 1).toUpperCase() + name.substring(1);
		for (int i=1; i<readableName.length(); ++i) {
			if (Character.isUpperCase(readableName.charAt(i))) {
				readableName = readableName.substring(0, i) + " " + readableName.substring(i);
				++i;
			}
		}
		return readableName;
	}

	protected String getGetValueTemplate(FieldType type) {
		switch(type) {
			case STRING:
			case TEXT:
				if (gvSimp == null) {
					gvSimp = readFile(getTemplateDir(), "getValueSimple.txt");
				}
				return gvSimp;
			case BOOL:
				if (gvBool == null) {
					gvBool = readFile(getTemplateDir(), "getValueBool.txt");
				}
				return gvBool;
			case DOUBLE:
				if (gvDouble == null) {
					gvDouble = readFile(getTemplateDir(), "getValueDouble.txt");
				}
				return gvDouble;
			case INT:
				if (gvInt == null) {
					gvInt = readFile(getTemplateDir(), "getValueInt.txt");
				}
				return gvInt;
			case REF:
				if (gvRef == null) {
					gvRef = readFile(getTemplateDir(), "getValueRef.txt");
				}
				return gvRef;
			case UNKNOWN:
			default:
				Logger.getLogger(ObjectGenerator.class.getName()).log(Level.SEVERE, null, (Throwable)null);
				popErrorDialog("A programmer error has resulted in a variable type being unknown.  Please contact the developer and chew him out.");
				return null;
		}
	}

	protected String getSetValueTemplate(FieldType type) {
		switch(type) {
			case STRING:
			case TEXT:
				if (svSimp == null) {
					svSimp = readFile(getTemplateDir(), "setValueSimple.txt");
				}
				return svSimp;
			case BOOL:
				if (svBool == null) {
					svBool = readFile(getTemplateDir(), "setValueBool.txt");
				}
				return svBool;
			case DOUBLE:
				if (svDouble == null) {
					svDouble = readFile(getTemplateDir(), "setValueDouble.txt");
				}
				return svDouble;
			case INT:
				if (svInt == null) {
					svInt = readFile(getTemplateDir(), "setValueInt.txt");
				}
				return svInt;
			case REF:
				// Not an error.
				return null;
			case UNKNOWN:
			default:
				Logger.getLogger(ObjectGenerator.class.getName()).log(Level.SEVERE, null, (Throwable)null);
				popErrorDialog("A programmer error has resulted in a variable type being unknown.  Please contact the developer and chew him out.");
				return null;
		}
	}

	protected String getJavaType(FieldType type) {
		switch (type) {
			case STRING:
			case TEXT:
				return "String";
			case INT:
				return "int";
			case DOUBLE:
				return "double";
			case BOOL:
				return "boolean";
			case REF:
				return "ReferenceUI";
			case UNKNOWN:
			default:
				Logger.getLogger(ObjectGenerator.class.getName()).log(Level.SEVERE, null, (Throwable)null);
				popErrorDialog("A programmer error has resulted in a variable type being unknown.  Please contact the developer and chew him out.");
				return null;
		}
	}

	protected String getDisplayType(FieldType type) {
		switch (type) {
			case STRING:
			case INT:
			case DOUBLE:
				return "TEXT_BOX";
			case TEXT:
				return "TEXT_AREA";
			case BOOL:
				return "CHECK_BOX";
			case REF:
				return "REFERENCE";
			case UNKNOWN:
			default:
				Logger.getLogger(ObjectGenerator.class.getName()).log(Level.SEVERE, null, (Throwable)null);
				popErrorDialog("A programmer error has resulted in a variable type being unknown.  Please contact the developer and chew him out.");
				return null;
		}
	}
}
